package top.amot.forceview.force

import androidx.annotation.CallSuper
import androidx.annotation.FloatRange
import top.amot.forceview.layout.I_Layout
import top.amot.forceview.model.AbstractLink
import top.amot.forceview.model.AbstractNode

interface Force {
    /**
     * optionally implement force.initialize to receive the simulation.
     */
    fun initialize(simulation: I_Layout)

    /**
     * apply this force to modify nodes’ positions or velocities.
     * @param alpha from 0 (inclusive) to 1 (inclusive), default 1
     */
    fun apply(@FloatRange(from = 0.0, to = 1.0) alpha: Float)

}

abstract class AbstractForce : Force {
        protected lateinit var layout: I_Layout
        protected val nodes get() = layout.currentNodeList()

        @CallSuper
        override fun initialize(layout: I_Layout) {
            this.layout = layout
        }

        companion object {
            @JvmStatic
            protected fun jiggle(): Float {
                return ((Math.random() - 0.5) * 1e-6).toFloat()
            }
        }
}

fun interface NodeCalculation {
    fun calculateNode(node: AbstractNode): Float
}

fun interface LinkCalculation {
     fun calculateLink(link: AbstractLink<AbstractNode,AbstractNode>): Float
}


class ConstantCalculation(var value: Float) : NodeCalculation, LinkCalculation {
    override fun calculateNode(node: AbstractNode): Float {
        return value
    }

    override fun calculateLink(link: AbstractLink<AbstractNode,AbstractNode>): Float {
        return value
    }

}